using System.Collections.Immutable;
using System.Diagnostics;
using DimensionsHelper.LanguageService.Symbols;
using DimensionsHelper.LanguageService.Syntax;

namespace DimensionsHelper.LanguageService;

public class AnalysisIndexExpression : AnalysisExpression
{
    internal AnalysisIndexExpression(IndexExpression syntaxNode, AnalysisNode? parent)
        : base(AnalysisBoundKinds.Index, syntaxNode, parent)
    {
        Syntax = syntaxNode;
    }
    
    private readonly List<AnalysisExpression> _arguments = [];

    public override IndexExpression Syntax { get; }

    public AnalysisExpression? Object { get; private set; }

    public override int ChildrenCount => _arguments.Count + (Object == null ? 0 : 1);


    public void SetObject(AnalysisExpression obj)
    {
        Debug.Assert(Object == null, "AnalysisIndexExpression.Object is already set.");
        Object = obj;
        Object.Parent = this;
    }


    public AnalysisExpression GetObject()
    {
        Debug.Assert(Object != null, "AnalysisIndexExpression has no object.");
        return Object;
    }


    public override IEnumerable<AnalysisNode> GetChildren()
    {
        return Object != null ? [Object, .._arguments] : _arguments.ToImmutableArray();
    }

    internal override void AddChild(AnalysisNode child)
    {
        Debug.Assert(child.IsExpression);
        child.Parent = this;
        _arguments.Add((AnalysisExpression)child);
    }
}

public static partial class AnalysisNodeFactory
{
    /// <summary>
    /// 创建一个索引表达式
    /// </summary>
    /// <param name="syntaxNode">原始的语法节点</param>
    /// <param name="obj">调用表达式</param>
    /// <param name="parent">父节点</param>
    /// <param name="withSymbol">此节点所处的With语句上下文类型符号</param>
    /// <param name="parameters">参数列表</param>
    public static AnalysisIndexExpression Index(IndexExpression syntaxNode, AnalysisExpression? obj,
        AnalysisNode? parent, ITypeSymbol? withSymbol, params AnalysisNode[] parameters)
    {
        AnalysisIndexExpression expr = new(syntaxNode, parent);

        if (obj != null)
        {
            expr.SetObject(obj);
        }

        foreach (var paramNode in parameters)
        {
            expr.AddChild(paramNode);
        }
        
        return expr.WithContainingWithSymbol(withSymbol);
    }
}